/**
 * AGNModelRenderer.java
 */
package agngui.agnmodel;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.AmbientLight;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Light;
import javax.media.j3d.PickRay;
import javax.media.j3d.PointLight;
import javax.media.j3d.Transform3D;
import javax.media.j3d.View;
import javax.swing.JFrame;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;

import com.sun.j3d.utils.universe.SimpleUniverse;

/** 
 * Handles all Java3D scene graph management
 * 
 * @author Philippe Johnson
 * @author Ben Bloom
 */
public class AGNModelRenderer {
	/**
	 * The system camera
	 */
	private AGNCamera      camera;
	
	/**
	 * The canvas that is being used to draw the view plate
	 */
    private AGNModelCanvas canvas       = null;
    
    /**
     * The universe in which everything in the system exists
     */
    private SimpleUniverse universe     = null;
    
    /**
     * The main light source of the system
     */
	private Light          light;
	
	/**
	 * The ambient light in the system
	 */
	private Light          ambient_light;
	
	/**
	 * The background of the system
	 */
	private Background     background;
	
	/**
	 * the off-screen canvas, used for taking screenshots
	 */
	private Canvas3D off_screen_canvas;
	
    /**
     * AGNModelRenderer
     * 
     * Sets up Java3D and attaches the canvas to a JFrame.
     *
     * @param window The JFrame to which the canvas will be attached.
     */
    public AGNModelRenderer( JFrame window) {
        // Grab configuration
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

        // Set up canvas, universe, and camera
        canvas = new AGNModelCanvas( config );
        off_screen_canvas = new Canvas3D(config, true);
        universe = new SimpleUniverse( canvas );
        universe.getViewer().getView().addCanvas3D(off_screen_canvas);
		camera = new AGNCamera(universe);
		Point3f light_position = new Point3f(0f,0f,0f);
		light = new PointLight(new Color3f(255, 255, 255), light_position, new Point3f(1, 0, 0.001f));
		light.setEnable(true);
		BoundingSphere sphere = new BoundingSphere(new Point3d(light_position), 1e6);
		light.setInfluencingBounds(sphere);
		
		ambient_light = new AmbientLight();

		ambient_light.setEnable(true);
		ambient_light.setColor(new Color3f(255,255,255));
		ambient_light.setCapability(AmbientLight.ALLOW_STATE_WRITE);
		ambient_light.setCapability(AmbientLight.ALLOW_COLOR_WRITE);
		ambient_light.setInfluencingBounds(sphere);
		
		View view = canvas.getView();
		view.setFrontClipDistance(0.001);
		view.setBackClipDistance(1000000);
		
		
		background = new Background(new Color3f(0,0,0));
		background.setCapability(Background.ALLOW_COLOR_WRITE);
		background.setCapability(Background.ALLOW_COLOR_READ);
		background.setApplicationBounds(sphere); 
		
        // Attach canvas to the JPanel
        window.add( canvas, BorderLayout.CENTER );
    }
    
    /**
     * sets the background of the canvas to the given color
     * @param color The color to set the background to
     */
    public void setBackgroundColor(Color3f color) {
    	background.setColor(color);
    }
	
    /**
     * getCamera
     *
     * Gets a reference to the renderer's camera
     *
     * @return a reference to this renderer's camera
     */
	public AGNCamera getCamera() { return camera; }
	
    /**
     * getCanvas
     *  
     * @return The renderer canvas
     */
    public AGNModelCanvas getCanvas() {
        return canvas;
    }

    /**
     * getClickRay
     * 
     * Generates a ray into the scene from a mouse click.
     *
     * @param mX The mouse click X coordinate.
     * @param mY The mouse click Y coordinate.
     * @return The ray into the 3D scene.
     */
    public PickRay getClickRay( int mX, int mY ) {
        Point3d eyePoint   = new Point3d();
        Point3d clickPoint = new Point3d();
        
        canvas.getCenterEyeInImagePlate( eyePoint );
        canvas.getPixelLocationInImagePlate( mX, mY, clickPoint );

        Transform3D projection = new Transform3D();
        canvas.getImagePlateToVworld( projection );
        projection.transform( eyePoint );
        projection.transform( clickPoint );

        Vector3d dir = new Vector3d( clickPoint );
        dir.sub( eyePoint );
		//System.out.println(mX + " " + mY + " " + eyePoint.toString() + " " + dir.toString());
        return new PickRay( eyePoint, dir );
    }
    
    /**
     * buildScene
     *
     * Compiles the scene graph for rendering!
     *
     * @param geometry The system geometry
     */
    public void buildScene( AGNModelGeometry geometry ) {
        BranchGroup system = geometry.getSystem();
		
		system.addChild(light);
		system.addChild(ambient_light);
		system.addChild(background);
        if( !system.isCompiled() ) {
			system.compile();
		}

        universe.addBranchGraph( system );
    }

    /**
     * This does not work for some reason.  There is a defect in Java3D that is causing it to not recognize
     * that a version of OpenGL which is installed is actually installed.
     * 
    public BufferedImage getScreenShot() {
    	BufferedImage image = new BufferedImage(canvas.getWidth(), canvas.getHeight(), BufferedImage.TYPE_INT_RGB);

    	ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGB, image);
    	Screen3D off = off_screen_canvas.getScreen3D();
    	off.setSize(canvas.getScreen3D().getSize());
    	off.setPhysicalScreenWidth(canvas.getScreen3D().getPhysicalScreenWidth());
    	off.setPhysicalScreenHeight(canvas.getScreen3D().getPhysicalScreenHeight());
    	off_screen_canvas.setOffScreenBuffer(buffer);
        off_screen_canvas.renderOffScreenBuffer();
        off_screen_canvas.waitForOffScreenRendering();
        image = off_screen_canvas.getOffScreenBuffer().getImage();
    	return image; 
    }*/
}
